package com.score;


import android.util.Log;

import java.io.RandomAccessFile;
import java.util.concurrent.locks.ReentrantLock;


public class DataBuffer {
	
	public static final String TAG = "DataBuffer";
	
	private byte[] mBuf;
	private int mCurPos = 0;
	private int mEndPos = 0;
	private int mBufSize = 0; 
	
	private final ReentrantLock _dataLock = new ReentrantLock();

	public DataBuffer(int size)
	{
		if(size <= 0)
			return;

		mBuf = new byte[size];
		mBufSize = size;
	}
	
	public byte[] getBuf()
	{
		return mBuf;
	}
	/**
	 * 
	 * @return 整个DataBuffer的长度
	 */
	public int getDataBufSize()
	{
		return mBufSize;
	}

	public int getCurPos()
	{
		return mCurPos;
	}
	
	public DataBuffer(byte[] buf, boolean isData)
	{
		mBuf = buf;
		mBufSize = buf.length;
		mCurPos = 0;
		if(isData)
			mEndPos = buf.length;
		else
			mEndPos = 0;
	}

	public DataBuffer(byte[] data, int offset, int len)
	{
		mBuf = data;
		mBufSize = data.length;
		mCurPos = offset;
		mEndPos = offset + len;
	}

	public int getLen()
	{
		_dataLock.lock();
		int len = mEndPos - mCurPos;

		if(len < 0)
			len = (len + mBufSize) % mBufSize;

		_dataLock.unlock();
		return len;
	}

	public int getLeft()
	{
		_dataLock.lock();
		int len = mBufSize - getLen();
		_dataLock.unlock();
		return len;
	}

	public boolean pushData(byte[] data)
	{
		if(getLeft() <= data.length)
		{
			int left = getLeft();
			throw new RuntimeException("pushData failt");
		}

		_dataLock.lock();
		if(mEndPos + data.length <= mBufSize)
		{
			System.arraycopy(data, 0, mBuf, mEndPos, data.length);
		}else{
			System.arraycopy(data, 0, mBuf, mEndPos, mBufSize-mEndPos);
			System.arraycopy(data, mBufSize-mEndPos, mBuf, 0, data.length - (mBufSize - mEndPos));
		}
		mEndPos = (mEndPos + data.length)%mBufSize;

		_dataLock.unlock();
		return true;
	}

	public boolean pushData(byte[] data, int offset, int len)
	{
		if(getLeft() < len || len <= 0)
			return false;

		_dataLock.lock();
		if(mEndPos + len < mBufSize)
		{
			System.arraycopy(data, offset, mBuf, mEndPos, len);
		}else{
			System.arraycopy(data, offset, mBuf, mEndPos, mBufSize-mEndPos);
			System.arraycopy(data, offset + mBufSize-mEndPos, mBuf, 0, len - (mBufSize - mEndPos));
		}

		mEndPos = (mEndPos + len)%mBufSize;

		_dataLock.unlock();
		return true;
	}

	public int lookValue(int pos)
	{
		if(getLen() < (pos + 1)*4)
			return 0;

		return  getValue(mBuf, mCurPos + pos*4);
	}
	
	public int lookData(int pos, byte[] data)
	{
		_dataLock.lock();

		int tempPos = mCurPos;
		mCurPos = pos;

/////////
		if(mCurPos + data.length <= mBufSize)
		{
			System.arraycopy(mBuf, mCurPos, data, 0, data.length);
		}else{
			System.arraycopy(mBuf, mCurPos, data, 0, mBufSize - mCurPos);
			System.arraycopy(mBuf, 0, data, mBufSize - mCurPos, data.length - (mBufSize - mCurPos));
		}

		mCurPos = (mCurPos + data.length)%mBufSize;
/////////		
		pos = mCurPos;
		mCurPos = tempPos;
		
		_dataLock.unlock();
		
		return pos;
		
	}

	static public int getValue(byte[] data, int offset)
	{
		return  data[0 + offset] & 0xff 
				 | (data[1 + offset] & 0xff) << 8 
				 | (data[2 + offset] & 0xff) << 16
				 | (data[3 + offset] & 0xff) << 24;
	}

	public boolean erase(int len)
	{
		if(getLen() < len || len <= 0)
			return false;

		_dataLock.lock();
		mCurPos = (mCurPos + len + mBufSize)%mBufSize;
		_dataLock.unlock();
		return true;
	}

	public boolean getData(byte[] data)
	{
		
		if(data == null || getLen() < data.length)
			return false;

		_dataLock.lock();
		if(mCurPos + data.length <= mBufSize)
		{
			System.arraycopy(mBuf, mCurPos, data, 0, data.length);
		}else{
			System.arraycopy(mBuf, mCurPos, data, 0, mBufSize - mCurPos);
			System.arraycopy(mBuf, 0, data, mBufSize - mCurPos, data.length - (mBufSize - mCurPos));
		}

		mCurPos = (mCurPos + data.length)%mBufSize;

		_dataLock.unlock();
		return true;
	}

	public boolean   getDataToFile(int len, RandomAccessFile recFile, RandomAccessFile accomFile, float fac, boolean isOrigin){
		if (getLen() < len)
			return false;
		_dataLock.lock();
		if(mCurPos + len <= mBufSize)
		{
			try {
				if (isOrigin){
					for (int i = 0; i<len; i+=4){
						mBuf[mCurPos + i + 2] = mBuf[mCurPos + i];
						mBuf[mCurPos + i + 3] = mBuf[mCurPos + i + 1];
					}
				}
				accomFile.write(mBuf,mCurPos,len);

				long startFacTime = System.currentTimeMillis();
				facAudio(mBuf, mCurPos, len, fac);
				//clearAudio(mBuf,mCurPos,len);
				Log.d(TAG, " fac use time : " + (System.currentTimeMillis() - startFacTime));
				recFile.write(mBuf,mCurPos,len);
			}catch (Exception e){
				e.printStackTrace();
			}
		}else{
			try {
				if (isOrigin){
					for (int i = 0; i<(mBufSize - mCurPos); i+=4){
						mBuf[mCurPos + i + 2] = mBuf[mCurPos + i];
						mBuf[mCurPos + i + 3] = mBuf[mCurPos + i + 1];
					}
				}
				accomFile.write(mBuf, mCurPos, mBufSize - mCurPos);
				facAudio(mBuf, mCurPos, (mBufSize - mCurPos), fac);
				//clearAudio(mBuf, mCurPos, (mBufSize - mCurPos));
				recFile.write(mBuf, mCurPos, mBufSize - mCurPos);

				if (isOrigin){
					for (int i = 0; i<(len - (mBufSize - mCurPos)); i+=4){
						mBuf[i + 2] = mBuf[ i];
						mBuf[i + 3] = mBuf[i + 1];
					}
				}
				accomFile.write(mBuf, 0, len - (mBufSize - mCurPos));
				facAudio(mBuf, mCurPos, (len - (mBufSize - mCurPos)), fac);
				//clearAudio(mBuf, mCurPos, (len - (mBufSize - mCurPos)));
				recFile.write(mBuf, 0, len - (mBufSize - mCurPos));
			}catch (Exception e){
				e.printStackTrace();
			}
		}

		mCurPos = (mCurPos + len)%mBufSize;

		Log.e("xxxx", "lookfor1 = " + mBuf[mCurPos] + ", " + mBuf[mCurPos+1] + ", len = " + getLen());

		_dataLock.unlock();
		return true;
	}
	/**
	 * 读取最后DataBuffer中长度小于data.length的数据，返回读取的长度
	 */
	int endLongth = 0;
	public int getEndData(byte[] data)
	{
		if(data == null )
			return 0;

		_dataLock.lock();
		if(mEndPos <= mBufSize)//_curPos + data.length <= _bufSize
		{
			//System.arraycopy(_buf, _curPos, data, 0, data.length);
			System.arraycopy(mBuf, mCurPos, data, 0, mEndPos - mCurPos);
			endLongth = mEndPos - mCurPos;
		}else{
			System.arraycopy(mBuf, mCurPos, data, 0, mBufSize - mCurPos);
			System.arraycopy(mBuf, 0, data, mBufSize - mCurPos, mEndPos);
			endLongth = mBufSize - mCurPos + mEndPos;
		}
		
		mCurPos = (mCurPos + endLongth)%mBufSize;
		
		_dataLock.unlock();
		return endLongth;
	}

	public boolean getRData(byte[] data)
	{
		if(getLen() < data.length)
			return false;

		_dataLock.lock();
		System.arraycopy(mBuf, mEndPos - data.length, data, 0, data.length);

		mEndPos = (mEndPos - data.length + mBufSize)%mBufSize;

		_dataLock.unlock();
		return true;
	}

	public boolean getData(byte[] data, int pos, int len)
	{
		if(getLen() < len)
			return false;

		_dataLock.lock();
		if(mCurPos + len <= mBufSize)
		{
			System.arraycopy(mBuf, mCurPos, data, pos, len);
		}else{
			System.arraycopy(mBuf, mCurPos, data, pos, mBufSize - mCurPos);
			System.arraycopy(mBuf, 0, data, pos + mBufSize - mCurPos, len - (mBufSize - mCurPos));
		}

		mCurPos = (mCurPos + len)%mBufSize;

		_dataLock.unlock();
		return true;
	}

	private void facAudio(byte[] buf,int offset,int len,float fac){
		for (int i = 0;i<len/2;i++){
			int pos = offset + i*2;
			short audio = (short) (((buf[pos + 1] & 0xff) << 8) | (buf[pos] & 0xff));
			short facAudio = (short)(audio*fac);
			buf[pos] = (byte)facAudio;
			buf[pos + 1] = (byte)(facAudio>>8);
		}
	}
	private void clearAudio(byte[] buf,int offset,int len){
		for (int i= offset;i<(offset + len);i++){
			buf[i] = 0;
		}
	}
}